#region Using Statements
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using jaam_butters.Agents;
#endregion

enum Direction
{ 
    L = 0,
    R = 1,
    U = 2,
    D = 3
}

namespace jaam_butters
{
    /// <summary>
    /// This is a class to contain info on a command
    /// </summary>
    class Command
    {
        public Direction direction;
        public int spaces;
        public Rectangle dest;

        public Command(Direction d, int s)
        {
            direction = d;
            spaces = s;
        }
    }
    /// <summary>
    /// This is A game component that is notified when it needs to draw itself. 
    /// It implements IDrawable.
    /// </summary>
    public partial class Controller : Microsoft.Xna.Framework.DrawableGameComponent
    {
        SpriteBatch spritebatch;
        SpriteFont font;
        Texture2D commandSprites;
        Texture2D deathSprite;
        Texture2D winSprite;
        List<Command> freeCommands;
        List<Command> usedCommands;
        public bool running;
        int spriteHeight;
        static int tileWidth = 150;
        static int numTiles = 10;
        static int tileheight;
        static Texture2D regTile;
        static Texture2D runTile;
        static Texture2D stopTile;
        MouseState old;
        Rectangle runStopLocation;
        Jaam myJaam;
        public int deathFrames = 0;
        public int winFrames = -1;
        public Controller(Game game,Jaam jaam,SpriteBatch sb)
            : base(game)
        {
            // TODO: Construct any child components here
            myJaam = jaam;
            freeCommands = new List<Command>();
            usedCommands = new List<Command>();
            running = false;
            tileheight = (game.Window.ClientBounds.Height)/(numTiles+1);
            regTile = new Texture2D(Game.GraphicsDevice, 1, 1);
            regTile.SetData(new [] {Color.White});
            old = Mouse.GetState();
            runStopLocation = new Rectangle(0, Game.Window.ClientBounds.Height - tileheight, tileWidth, tileheight);
            addCommand(freeCommands, new Command(Direction.D, 2));
            addCommand(freeCommands, new Command(Direction.D, 1));
            addCommand(freeCommands, new Command(Direction.L, 3));
            addCommand(freeCommands, new Command(Direction.R, 2));
            addCommand(freeCommands, new Command(Direction.U, 2));
            addCommand(freeCommands, new Command(Direction.D, 1));
            addCommand(freeCommands, new Command(Direction.L, 4));
            addCommand(freeCommands, new Command(Direction.R, 2));
            spritebatch = sb;
            LoadContent();
        }

        /// <summary>
        /// Load content specific to your component.
        /// </summary>
        protected override void LoadContent()
        {
            // TODO: Load any content
            // command
            deathSprite = Game.Content.Load<Texture2D>("game over");
            winSprite = Game.Content.Load<Texture2D>("victory");
            commandSprites = Game.Content.Load<Texture2D>("directions");
            spriteHeight = commandSprites.Height;
            // tiles
            regTile = Game.Content.Load<Texture2D>("regTile");
            runTile = Game.Content.Load<Texture2D>("runTile");
            stopTile = Game.Content.Load<Texture2D>("stopTile");
            font = Game.Content.Load<SpriteFont>("myFont");
            //spritebatch = new SpriteBatch(Game.GraphicsDevice);
        }

        /// <summary>
        /// Allows the component to run logic such as updating the world,
        /// checking for collisions, gathering input and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        public override void Update(GameTime gameTime)
        {

            // TODO: Add your update logic here
            MouseState current = Mouse.GetState();
            if (current.LeftButton == ButtonState.Pressed && old.LeftButton != current.LeftButton)
            {
                if (!running)
                {
                    List<Command> toRemoveFromFree = new List<Command>();
                    List<Command> toRemoveFromUsed = new List<Command>();
                    foreach (Command i in freeCommands)
                    {
                        if (i.dest.Contains(current.X, current.Y))
                        {
                            toRemoveFromFree.Add(i);
                        }
                    }
                    foreach (Command i in usedCommands)
                    {
                        if (i.dest.Contains(current.X, current.Y))
                        {
                            toRemoveFromUsed.Add(i);
                        }
                    }
                    foreach (Command i in toRemoveFromFree)
                    {
                        freeCommands.Remove(i);
                        addCommand(usedCommands, i);
                    }
                    foreach (Command i in toRemoveFromUsed)
                    {
                        usedCommands.Remove(i);
                        addCommand(freeCommands, i);
                    }
                    updateRects(usedCommands);
                    updateRects(freeCommands);
                }
                if (runStopLocation.Contains(current.X, current.Y))
                {
                    running = !running;
                    if (running)
                    {
                        ///insert logic here for passing the list to Jaam
                        List<Vector2> commands = convertCommands(usedCommands);
                        myJaam.CommandReader(commands,this);
                    }
                    else
                    {
                        myJaam.ResetCommandReader();
                    }
                }
            }
            old = current;
            if (deathFrames > 0)
            {
                deathFrames--;
                if(deathFrames == 0)
                {
                    ((Jaam_Butters_Adventure)Game).ReturnToMenu();
                }
            }
            
            if (winFrames > 0)
            {
                winFrames--;

                if (winFrames == 0)
                {
                    ((Jaam_Butters_Adventure) Game).ReturnToMenu();
                }
            }
            //base.Update(gameTime);
        }

        /// <summary>
        /// This is called when the component should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        public override void Draw(GameTime gameTime)
        {
            string output;
            Vector2 fontOrigin;
            //spritebatch.Begin();
            // TODO: Add your drawing code here
            //draw left and right panels
            spritebatch.Draw(regTile, new Rectangle(0, 0, tileWidth, Game.Window.ClientBounds.Height), Color.White);
            spritebatch.Draw(regTile, new Rectangle(Game.Window.ClientBounds.Width - tileWidth, 0, tileWidth, Game.Window.ClientBounds.Height), Color.White);
            // draw USED
            spritebatch.Draw(regTile, new Rectangle(0, 0, tileWidth, tileheight), Color.White);
            //output = gameTime.ElapsedGameTime.ToString();
            output = "Used";
            fontOrigin = font.MeasureString(output) / 2;
            spritebatch.DrawString(font, output, new Vector2(tileWidth/2,tileheight/2)-fontOrigin,Color.Black);
            //draw FREE
            spritebatch.Draw(regTile, new Rectangle(Game.Window.ClientBounds.Width-tileWidth, 0, tileWidth, tileheight), Color.White);
            output = "Free";
            fontOrigin = font.MeasureString(output) / 2;
            spritebatch.DrawString(font, output, new Vector2(Game.Window.ClientBounds.Width - tileWidth/2, tileheight / 2) - fontOrigin, Color.Black);


            if (running)
            {
                spritebatch.Draw(stopTile, runStopLocation, Color.White);
                output = "Reset";
                fontOrigin = font.MeasureString(output) / 2;
                spritebatch.DrawString(font, output, (new Vector2(tileWidth/2, Game.Window.ClientBounds.Height - tileheight/2))-fontOrigin, Color.Black);
            }
            else
            {
                spritebatch.Draw(runTile, runStopLocation, Color.White);
                output = "Run";
                fontOrigin = font.MeasureString(output) / 2;
                spritebatch.DrawString(font, output, (new Vector2(tileWidth/2, Game.Window.ClientBounds.Height - tileheight/2))-fontOrigin, Color.Black);
            }
            for (int i = 0; i < usedCommands.Count; i++)
            {
                int tempDir = (int)usedCommands[i].direction;
                spritebatch.Draw(regTile, usedCommands[i].dest,Color.White);
                spritebatch.Draw(commandSprites, new Rectangle(tileheight / 4, Game.Window.ClientBounds.Height - (tileheight * (i + 2)) + tileheight / 4, tileheight/2, tileheight/2),
                                                new Rectangle(spriteHeight * (tempDir), 0, spriteHeight, spriteHeight),
                                                Color.White);
                output = usedCommands[i].spaces.ToString();
                fontOrigin = font.MeasureString(output)/2;
                spritebatch.DrawString(font, output, (new Vector2(tileWidth / 2, Game.Window.ClientBounds.Height - (tileheight * (i + 2)) + tileheight / 2)) - fontOrigin, Color.Black);
            }
            for (int i = 0; i < freeCommands.Count; i++)
            {
                int tempDir = (int)freeCommands[i].direction;
                spritebatch.Draw(regTile, freeCommands[i].dest, Color.White);
                spritebatch.Draw(commandSprites, new Rectangle(tileheight / 4 + Game.Window.ClientBounds.Width - tileWidth, Game.Window.ClientBounds.Height - (tileheight * (i + 2)) + tileheight / 4, tileheight / 2, tileheight / 2),
                                                new Rectangle(spriteHeight * (tempDir), 0, spriteHeight, spriteHeight),
                                                Color.White);
                output = freeCommands[i].spaces.ToString();
                fontOrigin = font.MeasureString(output) / 2;
                spritebatch.DrawString(font, output, (new Vector2(tileWidth / 2 + Game.Window.ClientBounds.Width - tileWidth, Game.Window.ClientBounds.Height - (tileheight * (i + 2)) + tileheight / 2)) - fontOrigin, Color.Black);
            }
            if (deathFrames > 0)
            {
                spritebatch.Draw(deathSprite, new Rectangle(0, 0, Game.Window.ClientBounds.Width, Game.Window.ClientBounds.Height), Color.White);
            }
            if (winFrames > 0)
            {
                spritebatch.Draw(winSprite, new Rectangle(0, 0, Game.Window.ClientBounds.Width, Game.Window.ClientBounds.Height), Color.White);
                
            }
            //spritebatch.End();
        }
        private void addCommand(List<Command> list, Command cmd)
        {
            if (list == usedCommands) {
                cmd.dest = new Rectangle(0, Game.Window.ClientBounds.Height - (tileheight * (list.Count + 2)), tileWidth, tileheight);
                list.Add(cmd);
            }
            if (list == freeCommands)
            {
                cmd.dest = new Rectangle(Game.Window.ClientBounds.Width - tileWidth, Game.Window.ClientBounds.Height - (tileheight * (list.Count + 2)), tileWidth, tileheight);
                list.Add(cmd);
            }
        }
        private void updateRects(List<Command> list)
        {
            int x;
            if(list==usedCommands) x = 0;
            else x = Game.Window.ClientBounds.Width - tileWidth;
            for (int i = 0; i < list.Count; i++)
            {
                list[i].dest = new Rectangle(x, Game.Window.ClientBounds.Height - (tileheight * (i + 2)), tileWidth, tileheight);
            }
        }
        private List<Vector2> convertCommands(List<Command> list)
        {
            List<Vector2> output = new List<Vector2>();
            foreach (Command i in list)
            {
                Vector2 temp;
                switch (i.direction)
                {
                    case Direction.U:
                        temp = new Vector2(0, -1);
                        break;
                    case Direction.D:
                        temp = new Vector2(0, 1);
                        break;
                    case Direction.L:
                        temp = new Vector2(-1, 0);
                        break;
                    case Direction.R:
                        temp = new Vector2(1, 0);
                        break;
                    default:
                        temp = new Vector2(0,0);
                        break;
                }
                temp *= i.spaces;
                output.Add(temp);
            }
            return output;
        }
    }
}


